package com.ebelter.btlibrary.btble.impl.scale;


import android.text.TextUtils;

import com.ebelter.btlibrary.btble.ble.bluetooth.callback.ConnectCallback;
import com.ebelter.btlibrary.btble.ble.bluetooth.device.impl.BleMessageAnalyser;
import com.ebelter.btlibrary.btble.ble.bluetooth.device.impl.Channel;
import com.ebelter.btlibrary.btble.ble.model.BtAck;
import com.ebelter.btlibrary.btble.impl.scale.callback.IMeasureResultCallback;
import com.ebelter.btlibrary.btble.impl.scale.callback.WeightUnitChangedCallback;
import com.ebelter.btlibrary.btble.impl.scale.common.ScaleAck;
import com.ebelter.btlibrary.btble.impl.scale.model.FatResult;
import com.ebelter.btlibrary.btble.impl.scale.model.OfflineMeasureResult;
import com.ebelter.btlibrary.btble.impl.scale.model.Scale;
import com.ebelter.btlibrary.btble.impl.scale.model.ScaleCommand;
import com.ebelter.btlibrary.btble.impl.scale.model.ScaleMeasureResult;
import com.ebelter.btlibrary.btble.impl.scale.model.ScaleUser;
import com.ebelter.btlibrary.btble.impl.scale.model.WeightUnit;
import com.ebelter.btlibrary.btble.impl.scale.upgrade.IFirmwareUpgradeCallback;
import com.ebelter.btlibrary.btble.util.MeasureResultAnalyzer;
import com.ebelter.btlibrary.util.ULog;

import java.util.Calendar;
import java.util.HashSet;

/**
 *  体脂秤数据解析器
 * Created by Sergio Pan on 2017/12/8.
 */

public class ScaleMessageAnalyser extends BleMessageAnalyser {

    private static final String TAG = "ScaleMessageAnalyser";

    private static ScaleMessageAnalyser instance = new ScaleMessageAnalyser();
    private HashSet<String> recordSet = new HashSet<String>();
    private long preScaleWakedTime;

    //数据解析后的各种回调
    private IMeasureResultCallback measureResultCallback;
    private ConnectCallback mConnectCallback;
    private WeightUnitChangedCallback unitChangedCallback;
    private IFirmwareUpgradeCallback firmwareUpgradeCallback;

    private ScaleMessageAnalyser() {
//        recordSet.
    }


    public static ScaleMessageAnalyser getInstance() {
        return instance;
    }

    public void registerConnectCallback(ConnectCallback callback) {
        this.mConnectCallback = callback;
    }

    public void registerMeasureResultCallback(IMeasureResultCallback callback) {
        this.measureResultCallback = callback;
    }

    public void registerWeightUnitChangedCallback(WeightUnitChangedCallback callback) {
        this.unitChangedCallback = callback;
    }

    public void registerFirmwareUpgradeCallback(IFirmwareUpgradeCallback callback) {
        this.firmwareUpgradeCallback = callback;
    }


    /**
     * 解密数据
     */
    @Override
    protected byte[] decrypt(byte[] data) {
//        ULog.i(TAG, "-------decrypt--------data = " + getArrayString(data));
        //TODO 如若是加密数据，在此做解密处理,如若非加密数据，可不重写此方法

        return data;
    }

    /**
     * 开始解析
     */
    @Override
    protected void analyze(Channel channel, byte[] data) {
        //解密后
        if (data.length < 2 || data[0] != dataHeaderReceive || data.length != (data[1] & 0xff) + 3) {
            return;
        }
        ULog.i(TAG, "-------analyze--------data = " + getArrayString(data));
        //业务码
        int cmdCode = data[2] & 0xff;
        ULog.i(TAG, "-------handlerData--------cmdCode = " + Integer.toHexString(cmdCode));
        switch (cmdCode) {
            case 0x00:
                break;
            case 0x90: //秤已唤醒
                onScaleWake(data);
                break;
            case 0x91: //秤已休眠
                onScaleSleep(data);
                break;
            case 0x92:        //称重单位
                ULog.i(TAG, "receive scale change unit.");
                onScaleUnitChanged(data);
                break;
            case 0x93:  //接收到第n组闹钟
                onReceiveAlarm(data);
                break;
            case 0x98: //接收到当前时钟
                onReceiveTime(data);
                break;
            case 0x9c: //接收到版本信息
                onReceiveScaleVersion(data);
                break;
            case 0x9e: //接收到体脂肪测量结果
                onReceiveMeasureResult(data);
                break;
            case 0xa0: //接收到历史测量数据
                onReceiveHistoryMeasureResult(data);
                break;
            case 0xa1:    //接收到升级包应答
                onUpgradeResponse(data);
                break;
            case 0xa2:    //升级结果
                onUpgradeResult(data);
                break;
            case 0xa3:    //体重数据
                break;
            case 0xa4:    //低电提示
                ULog.i(TAG, "receive device low power message.");
                onScaleLowPower(data);
                break;
            case 0xa5:    //测脂出错
                ULog.i(TAG, "receive fat measure error message.");
                if (measureResultCallback!=null)measureResultCallback.onFatMeasureError(data[3] & 0xff);
                break;
            case 0xa6:    //接收到修改闹钟ACK
                ULog.i(TAG, "receive set clock ack.");
//                expectAck = EnumAck.ACK_SET_ALARM;

//                ((IWeightMessageCallBack) msgCallBack).onSetClockAck();
                break;
            case 0xa7:    //接收到OTA升级就绪消息
                ULog.i(TAG, "receive OTA upgrade ready.");
                onOtaUpgradeReady(data);
                break;
            case 0xa8:    //接收到用户列表标记值响应

                break;
            case 0xa9:    //秤历史记录上传完毕消息
                ULog.i(TAG, "scale history uploaded done.");
                onHistoryDownloadDone(data);
                break;

            case 0xb0: //秤响应app的列表更新指令
                onUserInfoSettingSucceeded();
                break;

            case 0xb1://秤响应无连接前测量结果响应
                ULog.i(TAG, "scale response no before connect data.");
//                expectAck = EnumAck.ACK_GET_LAST_MEASURE;
//                ((IWeightMessageCallBack) msgCallBack).onGotLastRecordEmpty();
                break;
            case 0xb6: //上传秤是否与手机绑定过
                onAuthReult(data);
                break;
            case 0xb7:  //绑定确认指令
                onBindSuccess(data);
                break;
            case 0xb8:                //OTA sha256校验码下发响应
                onReceiveSha256Pkg(data);
                break;

        }


    }

    /**
     * 接收版本信息
     */
    private void onReceiveScaleVersion(byte[] data) {
        ULog.i(TAG, "----onReceiveScaleVersion----receive scale version info.");

        //ble固件
        int ble0 = data[3] & 0xff;
        int ble1 = data[4] & 0xff;
        //秤固件
        int scale0 = data[5] & 0xff;
        int scale1 = data[6] & 0xff;
        //系数固件
        int coefficientVer = get2ByteValue(data[7], data[8]);

        //算法固件
        int arithmeticVer = get2ByteValue(data[9], data[10]);

        int bleVer = (ble1 << 8) | ble0;
        int scaleVer = (scale1 << 8) | scale0;


        ULog.i(TAG, "receive scale version info." +
                "bleVer:" + bleVer +
                "scaleVer:" + scaleVer +
                "coefficientVer:" + coefficientVer +
                "arithmeticVer:" + arithmeticVer);

        //接收版本信息回调
        if(firmwareUpgradeCallback!=null){
            firmwareUpgradeCallback.onGotScaleVersion(bleVer, scaleVer, coefficientVer, arithmeticVer);
        }
        Scale.getInstance().setOtaVersion(scaleVer);
    }

    /**
     * 接收闹钟
     */
    private void onReceiveAlarm(byte[] data) {
        ULog.i(TAG, "-------onReceiveAlarm-----receive scale clock data.");
//        expectAck = EnumAck.ACK_GET_ALARM;

        int no = data[3] & 0xff;
        int hour = data[8] & 0xff;
        int minute = data[9] & 0xff;
        int clockRepeat = data[11] & 0xff;
        int onOrOff = clockRepeat & 128;
        int loonState = data[12] & 0xff;
//                    int[] clockRepeatArr = {
//                            (clockRepeat & 64) > 0 ? 1 : 0,
//                            (clockRepeat & 32) > 0 ? 1 : 0,
//                            (clockRepeat & 16) > 0 ? 1 : 0,
//                            (clockRepeat & 8) > 0 ? 1 : 0,
//                            (clockRepeat & 4) > 0 ? 1 : 0,
//                            (clockRepeat & 2) > 0 ? 1 : 0,
//                            (clockRepeat & 1) > 0 ? 1 : 0,
//                    };

//        int[] clockRepeatArr = {
//                (clockRepeat & 1) > 0 ? 1 : 0,
//                (clockRepeat & 2) > 0 ? 1 : 0,
//                (clockRepeat & 4) > 0 ? 1 : 0,
//                (clockRepeat & 8) > 0 ? 1 : 0,
//                (clockRepeat & 16) > 0 ? 1 : 0,
//                (clockRepeat & 32) > 0 ? 1 : 0,
//                (clockRepeat & 64) > 0 ? 1 : 0
//        };

        ULog.i(TAG, "receive clock data" +
                ",no: " + no +
                ",hour: " + hour +
                ",minute: " + minute +
                ",clockRepeat: " + Integer.toBinaryString(clockRepeat));
//        AlarmClock bean = new AlarmClock();
//        bean.setNo(no);
//        bean.setHour(hour);
//        bean.setMinute(minute);
//        bean.setOnOff(onOrOff > 0);
//        bean.setWeekRepeat(clockRepeatArr);
//        bean.setLoonState(loonState == 0);
//        ((IWeightMessageCallBack) msgCallBack).onGotAlarm(bean);
    }

    /**
     * 接收当前时间
     */
    private void onReceiveTime(byte[] data) {
        ULog.i(TAG, "----onReceiveAlarmClock---receive scale clock.");
//        expectAck = BleCommandEditor.EnumAck.ACK_SET_CLOCK;
        int year = get2ByteValue(data[3], data[4]);
        int month = data[5] & 0xff;
        int day = data[6] & 0xff;
        int hour = data[7] & 0xff;
        int minute = data[8] & 0xff;
        int second = data[9] & 0xff;

        int weekOfYear = data[10] & 0xff;

        ULog.i(TAG, "got scale curr clock info." +
                "year:" + year +
                "month:" + month +
                "day:" + day +
                "hour:" + hour +
                "minute:" + minute +
                "second:" + second +
                "weekOfYear:" + weekOfYear);

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DATE, day);
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, minute);
        cal.set(Calendar.SECOND, second);

        long scaleDateLong = cal.getTimeInMillis();
        if (measureResultCallback != null) {
            measureResultCallback.onReceiveTime(scaleDateLong);
        }

    }

    /**
     * 秤唤醒
     */
    private void onScaleWake(byte[] data) {
        ULog.i(TAG, "-----onScaleWake------receive scale wakeup.data[2] = " + Integer.toHexString(data[2] & 0xff));
        recordSet.clear();
        if (mConnectCallback != null && System.currentTimeMillis() - preScaleWakedTime > 2000) {
            preScaleWakedTime = System.currentTimeMillis();
            mConnectCallback.onScaleWake();
        }

        //秤唤醒后，需设置用户信息
        if (mInternalChannel != null) {
            mInternalChannel.sendCommnd(ScaleCommand.HEART_BEART);
        }
//        //秤唤醒后，需设置用户信息
//        if (mInternalChannel != null) {
//            mInternalChannel.sendCommnd(ScaleCommand.SET_USER_INFO);
//        }

    }

    /**
     * 秤休眠
     *
     * @param data
     */
    private void onScaleSleep(byte[] data) {
        ULog.i(TAG, "-----onScaleSleep------receive scale sleep.data[2] = " + Integer.toHexString(data[2] & 0xff));
        if (mConnectCallback != null) {
            mConnectCallback.onScaleSleep();
        }


    }

    /**
     * 体重单位改变
     *
     * @param data
     */
    private void onScaleUnitChanged(byte[] data) {
        WeightUnit scaleUnit = data[3] == 1 ? WeightUnit.KG : WeightUnit.LB;
        if (unitChangedCallback != null) {
            unitChangedCallback.onWeightUnitChanged(scaleUnit);
        }
    }

    /**
     * 用户信息设置成功
     */
    private void onUserInfoSettingSucceeded() {
        ULog.i(TAG, "------onUserInfoSettingSucceeded------scale response update list.");
//                expectAck = EnumAck.ACK_SET_CUSTOM;
        //TODO 用户信息更新成功回调
//        ((IWeightMessageCallBack) msgCallBack).onListUpdate();

        //用户列表更新成功后，发送同步时钟到秤端
        //mInternalChannel.sendCommnd(ScaleCommand.SYNC_CLOCK);
        mInternalChannel.updateRespondAck(new BtAck(ScaleAck.ACK_SET_CUSTOM));
        if(measureResultCallback!=null){
            measureResultCallback.updateUserInfoSuccess();
        }
    }

    private String lastReceiveMesureDataTime;
    /**
     * 接收到测量数据
     */
    private void onReceiveMeasureResult(byte[] data) {
       // ULog.i(TAG, "------onReceiveMeasureResult---------receive fat result data = " + getArrayString(data));
        mInternalChannel.sendCommnd(ScaleCommand.SEND_RECEIVED_ACK);
        if (measureResultCallback!=null){measureResultCallback.sendGetMesureDataACK();}

        FatResult fatResultBean = getFatResult(data);
        if (fatResultBean == null) {
            return;
        }
        ULog.i(TAG, "----onReceiveMeasureResult---------fatResultBean = " + fatResultBean.toString());
        ScaleMeasureResult result = MeasureResultAnalyzer.getInstance().getMeasureResult(fatResultBean, ScaleUser.getUser());
        if (TextUtils.equals(result.getMeasureTime(),lastReceiveMesureDataTime)){
            //说明上一次接收到的时间跟这一次是一样的
            return;
        }
        lastReceiveMesureDataTime=result.getMeasureTime();
        if (measureResultCallback != null) {
            measureResultCallback.onReceiveMeasureResult(result);
        }

    }


    private String lastReceiveHistoryMeasureResultTime;
    /**
     * 接收到历史测量数据
     */
    private void onReceiveHistoryMeasureResult(byte[] data) {
        ULog.i(TAG,"历史数据---接收到的元数据="+getArrayString(data));//
        if (measureResultCallback!=null){measureResultCallback.sendGetHisDataACK();}

//        expectAck = EnumAck.ACK_GET_RECOED;
        mInternalChannel.updateRespondAck(new BtAck(ScaleAck.ACK_GET_RECOED));
        FatResult fatResultBean = getFatResult(data);
        if (fatResultBean == null) {
            return;
        }
        //是否疑似数据
        int suspectedData = data[18];
        //是否疑似数据
        fatResultBean.setSuspectedData((suspectedData & 0xff) == 170);

        ULog.i(TAG, "receive history data : " + fatResultBean.toString());

        OfflineMeasureResult result = MeasureResultAnalyzer.getInstance().getOfflineMeasureResult(fatResultBean, ScaleUser.getUser());
        if (measureResultCallback != null) {

            String mt = result.getMeasureTime();
            if (TextUtils.isEmpty(mt)){
                ULog.i(TAG,"--onReceiveHistoryMeasureResult--接收到的离线数据时间为空 被return了");
                return;
            }

            if (TextUtils.equals(mt,lastReceiveHistoryMeasureResultTime)){
                ULog.i(TAG,"--onReceiveHistoryMeasureResult--接收到的离线数据时间  与上一次的时间一样 被return了 lastReceiveHistoryMeasureResultTime = "+lastReceiveHistoryMeasureResultTime);
                return;
            }
            lastReceiveHistoryMeasureResultTime=mt;

            measureResultCallback.onReceiveHistoryRecord(result);
        }

    }


    /**
     * 升级应答
     * @param data
     */
    private void onUpgradeResponse(byte[] data) {
//        expectAck = EnumAck.ACK_SET_OTA;

        int pkg1 = data[3] & 0xff;
        int pkg2 = data[4] & 0xff;
        int pkg = (pkg2 << 8) | pkg1;
        ULog.i(TAG, "-----onUpgradeResponse-----redevice packageupgradeResponse is:" + pkg);
        if (firmwareUpgradeCallback != null) {
            if ((data[5] & 0xff) <= 1) {
                firmwareUpgradeCallback.onUpgradeResponse(pkg, (data[5] & 0xff) == 0);
            } else {
                firmwareUpgradeCallback.onUpgradeResponse(pkg, true);
            }
        }
    }

    /**
     *  升级结果
     * @param data
     */
    private void onUpgradeResult(byte[] data) {
//        expectAck = EnumAck.ACK_SET_OTA;
        int result = data[3] & 0xff;
        int type = data[4] & 0xff;
        ULog.i(TAG, "---onUpgradeResult----package upgrade result:" + result);
        if (firmwareUpgradeCallback != null) {
            firmwareUpgradeCallback.onUpgradeResult(result, type);
        }
    }


    /**
     * 低电提醒
     * @param data
     */
    private void onScaleLowPower(byte[] data){
        if(firmwareUpgradeCallback != null){
            firmwareUpgradeCallback.onLowPower();
        }
    }

    /**
     * 固件升级就绪
     * @param data
     */
    private void onOtaUpgradeReady(byte[] data){
//        expectAck = EnumAck.ACK_GET_OTA_UPGRADE_REQ;
        if(firmwareUpgradeCallback!=null){
            firmwareUpgradeCallback.onOtaUpgradeReady(data[3] == 0);
        }
    }

    /**
     * 获取历史数据完成
     * @param data
     */
    private void onHistoryDownloadDone(byte[] data){
//                expectAck = EnumAck.ACK_GET_RECOED;
        if(measureResultCallback!=null){
            measureResultCallback.onHistoryDownloadDone();
        }
    }



    private void onAuthReult(byte[] data){
        if (data[3] == 1) {
//            ((IWeightMessageCallBack) msgCallBack).onAuthSuccess();
        } else {
//            ((IWeightMessageCallBack) msgCallBack).onAuthFailed();
        }
    }

    private void onBindSuccess(byte[] data){
//        ((IWeightMessageCallBack) msgCallBack).onBindSuccess();
    }

    private void onReceiveSha256Pkg(byte[] data){
        if (data[3] == 1) {
//            ((IWeightMessageCallBack) msgCallBack).onReceiveSha256PkgOne();
        } else {
//            ((IWeightMessageCallBack) msgCallBack).onReceiveSha256PkgTwo();
        }
    }



    private FatResult getFatResult(byte[] data) {
        if (data == null || data.length < 18) {
            return null;
        }
        int userId = data[3] & 0xff;
        float weight = get2ByteValue(data[5], data[4]) / 10.0f;
        float fat = get2ByteValue(data[7], data[6]) / 10.0f;
        //时间
        int year = get2ByteValue(data[9], data[8]);
        int month = data[10] & 0xff;
        int day = data[11] & 0xff;
        int hour = data[12] & 0xff;
        int minute = data[13] & 0xff;
        int second = data[14] & 0xff;
        int weekOfYear = data[15] & 0xff;

        //"testDate":"2018-03-15 12:11:12"

        //过滤重复的测量时间结果
        String testTime = new StringBuffer().append(year).append("-").append(month).append("-").append(day).append("-").append(hour).append("-").append(minute).append("-").append(second).toString();
        if (recordSet.contains(testTime)) {
            ULog.e(TAG, "receive same test time." + testTime);
            return null;
        }
        recordSet.clear();//zcq加于201804241520 一开始没有这一句 这个对象集合会越来越大 为了防止越来大
        recordSet.add(testTime);

        //电阻
        int resistance = get2ByteValue(data[17], data[16]);

        FatResult fatResultBean = new FatResult();
        fatResultBean.setUserId(userId);

        fatResultBean.setYear(year);
        fatResultBean.setMonth(month);
        fatResultBean.setDay(day);
        fatResultBean.setHour(hour);
        fatResultBean.setMinute(minute);
        fatResultBean.setSecond(second);

        fatResultBean.setWeekOfYear(weekOfYear);

        fatResultBean.setResistance(resistance);

        fatResultBean.setWeight(weight);
        fatResultBean.setFat(fat);

        boolean isUnitKg;
        int unitByte= (data[18] & 0xff);
        isUnitKg = 0x01 != unitByte;//判断传过来的单位类型

        fatResultBean.setUnitIsKG(isUnitKg);

        return fatResultBean;
    }

    @Override
    public void onRelease() {
        super.onRelease();


    }
}
